﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Diagnostics;

namespace ScriptIT
{
    public partial class frmMain : Form
    {
        Tables oTBLs;
        Tables oSingleTables;
        public frmMain()
        {
            InitializeComponent();
            oTBLs = new Tables();
            oTBLs.CurrentProgress += new Tables.CurrentProgressHandler(oTBLs_CurrentProgress);
            oTBLs.CurrentStatus += new Tables.CurrentStatusHandler(oTBLs_CurrentStatus);

            oSingleTables = new Tables();
            oSingleTables.CurrentProgress += new Tables.CurrentProgressHandler(oTBLs_CurrentProgress);
            oSingleTables.CurrentStatus += new Tables.CurrentStatusHandler(oTBLs_CurrentStatus);
        }

        private void tsExit_Click(object sender, EventArgs e)
        {
            this.Close();
            this.Dispose();
        }

        private void frmMain_Load(object sender, EventArgs e)
        {
            Databases oDBs = new Databases();
            foreach (Database oDB in oDBs)
            {
                tsDBCombo.ComboBox.Items.Add(oDB);
            }
            string sNew = "<Manage DBs>";
            tsDBCombo.ComboBox.Items.Add(sNew);
            Options.LoadOptions();
        }

        private void tsDBCombo_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (tsDBCombo.ComboBox.SelectedItem.ToString() == "<Manage DBs>")
            {
                frmDatabases oFrm = new frmDatabases();
                oFrm.Show(this);
                Databases oDBs = new Databases();
                
                tsDBCombo.Items.Clear();

                foreach (Database oDB in oDBs)
                {
                    tsDBCombo.ComboBox.Items.Add(oDB);
                }
            }
        }

        private void tsLoadDB_Click(object sender, EventArgs e)
        {
            try
            {
                Database selecteDB = (Database)tsDBCombo.SelectedItem;
                oTBLs.DataBase = selecteDB;
                oTBLs.Refresh();
                oSingleTables.DataBase = selecteDB;
                oTBLs_CurrentStatus("Displaying Tables");
                dgwTables.DataSource = oTBLs.AsList;
                dgwTables.Refresh();
                cmbSingleTables.DataSource = oTBLs.AsList;
                cmbSingleTables.Refresh();
                oTBLs_CurrentProgress(0.00);
                oTBLs_CurrentStatus("Ready");
                if (tabMain.SelectedTab == tabMain.TabPages[0])
                    dgwTables.Focus();
                else
                    cmbSingleTables.Focus();
            }
            catch (SqlException ex)
            {
                MessageBox.Show("Error while connecting to selected database." + Environment.NewLine + Environment.NewLine + ex.Message,"Error",MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            catch (Exception ex)
            {
                MessageBox.Show("Generla exception while selecting database." + Environment.NewLine + Environment.NewLine + ex.Message,"Error",MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

        }

        private void dgwTables_CellContentClick(object sender, DataGridViewCellEventArgs e)
        {

        }

        private void dgwTables_RowEnter(object sender, DataGridViewCellEventArgs e)
        {
            if (dgwTables.Rows[e.RowIndex].DataBoundItem == null)
                return;
            dgwColumns.DataSource= ((Table)dgwTables.Rows[e.RowIndex].DataBoundItem).Columns.AsList;
        }

        private void tsExecute_Click(object sender, EventArgs e)
        {
            string sSQL = string.Empty;

            try
            {
                Database oDatabase = (Database)tsDBCombo.SelectedItem;
                if (tabMain.SelectedTab == tabMain.TabPages[0])
                {
                    sSQL = ((Table)dgwTables.SelectedRows[0].DataBoundItem).GetSelectSQL();
                    try
                    {
                        DataSet dset = oDatabase.ExecuteDataset(sSQL);


                    if ((dset != null) && (dset.Tables.Count > 0))
                        dgwData.DataSource = dset.Tables[0];
                    else
                        dgwData.DataSource = null;
                    }
                    catch (SqlException sex)
                    {
                        if (sex.Number == 208)
                            MessageBox.Show("Seems the table does not belong to selected database or the database is modified since last load.", "SQL Error", MessageBoxButtons.OK);
                    }           }
                else
                {
                    sSQL = ((Table)dgwSingleTables.SelectedRows[0].DataBoundItem).SelectStatement;
                    DataSet dset = oDatabase.ExecuteDataset(sSQL);
                    if ((dset != null) && (dset.Tables.Count > 0))
                        dgwSingleData.DataSource = dset.Tables[0];
                    else
                        dgwSingleData.DataSource = null;
                }
            }
            catch (Exception ex)
            {
                ShowError(ex, false);
            }
        }

        private void ShowError(Exception ex, bool bShowContinue)
        {
            MessageBoxButtons oButton = MessageBoxButtons.OK;
            if (bShowContinue)
                oButton = MessageBoxButtons.YesNo;
            if (ex.InnerException == null)
                MessageBox.Show("Error Occured while fatching record. Please review Error string below." + System.Environment.NewLine + System.Environment.NewLine + "Exception: " + ex.Message, "Error",oButton );
            else
                MessageBox.Show("Error Occured while fatching record. Please review Error string below." + System.Environment.NewLine + System.Environment.NewLine + "Exception: " + ex.Message + System.Environment.NewLine + "Inner Exception: " + ex.InnerException.Message, "Error", oButton);
            
        }

        private void tsScript_Click(object sender, EventArgs e)
        {
            bool isFile;
            string path = GetPath(out isFile);
            bool isEmail = ((Options.eOutPutType)Options.OutPutType == Options.eOutPutType.EmailSingleZipFile);
            bool isZipFile = ((Options.eOutPutType)Options.OutPutType == Options.eOutPutType.SingleZipFile || isEmail); 
            string sTempPath = System.Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + Path.DirectorySeparatorChar + "ScriptITFiles" + Path.DirectorySeparatorChar;
            bool success ;

            //ToDO: Generate in Temp path and copy
            if (!Directory.Exists(sTempPath))
                Directory.CreateDirectory(sTempPath);
            else
                CleanUpPath(sTempPath);

            if (tabMain.SelectedTab == tabMain.TabPages[0])
            {
                dgwTables.Update();
                success = oTBLs.ScriptToPath(sTempPath);
            }
            else
            {
                dgwSingleTables.Update();
                success = oSingleTables.ScriptToPath(sTempPath);
            }

            if (isZipFile)
            {
                CreateZip(sTempPath, path);
                //if (isEmail)
                //    SendMail(sTempPath + Path.GetFileName(path));
                //else
                //    File.Copy(sTempPath + Path.GetFileName(path), path, true);
            }
            else if (isFile)
                MergeFiles(sTempPath, path);
            else
                MoveFiles(sTempPath, path);

            if (Options.OpenExportFile)
            {
                string pathtoopen = path;
                if (isFile)
                {
                    pathtoopen =  Path.GetDirectoryName(path);
                }
                else
                    Process.Start(pathtoopen);
            }
            oTBLs_CurrentProgress(0.00);
            oTBLs_CurrentStatus("Ready");
        }

        private void MoveFiles(string sTempPath, string path)
        {
            foreach (string file in Directory.GetFiles(sTempPath))
            {
                File.Copy(file, path + Path.DirectorySeparatorChar + Path.GetFileName(file), true);
            }
        }

        private void MergeFiles(string sTempPath, string path)
        {
            FileStream fsSrc = null;
            FileStream fsDest = null;

            try
            {

                fsDest = File.Open(path, FileMode.Append);
                foreach (string file in Directory.GetFiles(sTempPath))
                {
                    fsSrc = File.Open(file, FileMode.Open);
                    byte[] fs2Content = new byte[fsSrc.Length];
                    fsSrc.Read(fs2Content, 0, (int)fsSrc.Length);
                    fsDest.Write(fs2Content, 0, (int)fsSrc.Length);
                    fsSrc.Close();
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message + " : " + ex.StackTrace);
            }
            finally
            {
                fsDest.Close();
            }
        }

        private void SendMail(string p)
        {
            throw new NotImplementedException();
        }

        private void CreateZip(string sTempPath, string sZipFileName)
        {

            if (File.Exists(sZipFileName))
                File.Delete(sZipFileName);
            //Copy a folder and its contents into the newly created zip file
            Shell32.ShellClass sc = new Shell32.ShellClass();
            Shell32.Folder SrcFlder = sc.NameSpace(sTempPath);
            Shell32.FolderItems items = SrcFlder.Items();

            //Create an empty zip file
            byte[] emptyzip = new byte[] { 80, 75, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };

            FileStream fs = File.Create(sZipFileName);
            fs.Write(emptyzip, 0, emptyzip.Length);
            fs.Flush();
            fs.Close();
            fs = null;

            Shell32.Folder DestFlder = sc.NameSpace(sZipFileName);
            DestFlder.CopyHere(items, 20);

            //Ziping a file using the Windows Shell API creates another thread where the zipping is executed.
            //This means that it is possible that this console app would end before the zipping thread 
            //starts to execute which would cause the zip to never occur and you will end up with just
            //an empty zip file. So wait a second and give the zipping thread time to get started
            System.Threading.Thread.Sleep(1000);
        }

        private void CleanUpPath(string sTempPath)
        {
            DirectoryInfo directoryInfo = new DirectoryInfo(sTempPath);
            foreach (FileInfo fileInfo in directoryInfo.GetFiles()) fileInfo.Delete();
            foreach (DirectoryInfo childDirectories in directoryInfo.GetDirectories()) childDirectories.Delete(true);
        }

        private string GetPath(out bool isFile)
        {
            isFile = false;
            string sRetPath = string.Empty;
            string sFilter = string.Empty;
            string sDefaultFileName = "SQLScript_" + DateTime.Now.ToString("MMMddyyyy_hhmmss");

            switch ((Options.eOutPutType)Options.OutPutType)
            {
                case (Options.eOutPutType.SingleScriptFile):
                    {
                        isFile = true;
                        sFilter = "SQL File|*.SQL";
                        sDefaultFileName += ".SQL";
                        break;
                    }
                case (Options.eOutPutType.Separatefiles):
                    {
                        isFile = false;
                        break;
                    }
                case (Options.eOutPutType.SingleZipFile):
                    {
                        isFile = true;
                        sFilter = "ZIP File|*.ZIP";
                        sDefaultFileName += ".ZIP";
                        break;
                    }
                case (Options.eOutPutType.EmailSingleZipFile):
                    {
                        isFile = true;
                        sDefaultFileName += ".ZIP";
                        break;
                    }
            }

            switch ((Options.eDefaultLocType)Options.OutPutLocation)
            {
                case (Options.eDefaultLocType.AskEveryTime):
                    {
                        if (isFile)
                        {
                            dlgSaveAs.AddExtension = true;
                            dlgSaveAs.CheckPathExists = true;
                            dlgSaveAs.Filter = sFilter;
                            dlgSaveAs.Title = "Script IT | Save File as...";
                            dlgSaveAs.FileName = sDefaultFileName;
                            dlgSaveAs.InitialDirectory = Options.LastUsedFoler;
                            if (dlgSaveAs.ShowDialog() == DialogResult.OK)
                            {
                                sRetPath = dlgSaveAs.FileName;
                                Options.LastUsedFoler = Path.GetDirectoryName(sRetPath);
                                Options.SaveOptions();
                            }
                        }
                        else
                        {
                            dlgSavePath.SelectedPath = Options.LastUsedFoler;
                            dlgSavePath.Description = "Select a Path to store the generated Scripts.";
                            if (dlgSavePath.ShowDialog() == DialogResult.OK)
                            {
                                sRetPath = dlgSavePath.SelectedPath;
                                Options.LastUsedFoler = sRetPath;
                                Options.SaveOptions();
                            }
                        }

                        break;
                    }
                case (Options.eDefaultLocType.LastUsedFolder):
                    {
                        if (isFile)
                            sRetPath = Options.LastUsedFoler + @"\" + sDefaultFileName;
                        else
                            sRetPath = Options.LastUsedFoler + @"\";
                        break;
                        break;
                    }
                case (Options.eDefaultLocType.MyDocuments):
                    {
                        string spath = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal);
                        if (isFile)
                            sRetPath = spath + @"\" + sDefaultFileName;
                        else
                            sRetPath = spath + @"\";
                        break;
                    }
                case (Options.eDefaultLocType.Desktop):
                    {
                        string spath = System.Environment.GetFolderPath(System.Environment.SpecialFolder.DesktopDirectory);
                        if (isFile)
                            sRetPath = spath + @"\" + sDefaultFileName;
                        else
                            sRetPath = spath + @"\";
                        break;
                    }
                case (Options.eDefaultLocType.Custom):
                    {
                        if (isFile)
                            sRetPath = Options.CustomPath + @"\" + sDefaultFileName;
                        else
                            sRetPath = Options.CustomPath + @"\";
                        break;
                        break;
                    }

            }
            return sRetPath;
        }

        void oTBLs_CurrentStatus(string message)
        {
            tsStatus.Text = message;
            Application.DoEvents();
        }

        void oTBLs_CurrentProgress(double Progress)
        {
            if (Progress > 0)
                tsProgress.Visible = true;
            else
                tsProgress.Visible = false;

            tsProgress.Value = Convert.ToInt32(Progress) ;
        }

        private void tsSaveTmplt_Click(object sender, EventArgs e)
        {
            string sXML = string.Empty;
            if (tabMain.SelectedTab == tabMain.TabPages[0])
                sXML = oTBLs.ToXML(true, true);
            else
                sXML = oSingleTables.ToXML(true, true);

            if (sXML != string.Empty)
            {
                dlgSaveAs.Filter = "*.XML|*.xml";
                try
                {
                    dlgSaveAs.DefaultExt = "XML";
                    dlgSaveAs.ShowDialog(this);
                    StreamWriter oStream = new StreamWriter(dlgSaveAs.FileName);
                    oStream.Write(sXML);
                    oStream.Close();
                }
                catch
                {}
            }
        }

        private void tsLoadTmplt_Click(object sender, EventArgs e)
        {
            OpenFileDialog oDlg = new OpenFileDialog();
            oDlg.Filter = "*.XML|*.XML";
            oDlg.CheckFileExists = true;
            if (oDlg.ShowDialog(this) == DialogResult.OK)
            {
                Tables oTmplt = new Tables();
                try
                {
                    oTmplt.FromXML(oDlg.FileName);
                }
                catch (Exception ex)
                {
                }
                if (tsDBCombo.Text == string.Empty)
                {
                    int iSelected = tsDBCombo.FindStringExact(oTmplt.DataBase.Name);
                    if (iSelected == -1)
                    {
                        tsDBCombo.ComboBox.Items.Add(oTmplt.DataBase);
                        tsDBCombo.SelectedItem = oTmplt.DataBase;
                    }
                    else
                        tsDBCombo.SelectedIndex = iSelected;
                    tsLoadDB_Click(null, null);
                }
                else if (tsDBCombo.Text != oTmplt.DataBase.Name)
                {
                    if (MessageBox.Show("Selected Template does not belongs to loaded database.\nWould you like to load the database of the selected template?", "Load Template", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No)
                        return;
                    int iSelected = tsDBCombo.FindStringExact(oTmplt.DataBase.Name);
                    if (iSelected == -1)
                    {
                        tsDBCombo.ComboBox.Items.Add(oTmplt.DataBase);
                        tsDBCombo.SelectedItem = oTmplt.DataBase;
                    }
                    else
                        tsDBCombo.SelectedIndex = iSelected;
                    tsLoadDB_Click(null, null);
                }
                
                if (tabMain.SelectedTab == tabMain.TabPages[0])
                {
                    selectItems(oTmplt);
                }
                else
                {
                    dgwSingleTables.DataSource = null;
                    dgwSingleTables.DataSource = oTmplt.AsList;
                    dgwSingleTables.Refresh();
                }
            }
            oTBLs_CurrentStatus("Ready");
        }

        private void selectItems(Tables oTmplt)
        {
            List<Table> oTmpltList = oTmplt.AsList;
            List<Table> oGridList = (List<Table>) dgwTables.DataSource;
            for (int i = 0; i < oTmpltList.Count; i++)
            {
                for (int j = 0; j < oGridList.Count;j++ )
                {
                    if (oGridList[j].Name == oTmpltList[i].Name)
                    {
                        oGridList[j] = oGridList[j] + oTmpltList[i];
                        break;
                    }
                }
            }
            dgwTables.DataSource = null;
            dgwTables.DataSource = oGridList;
        }

        private void dgwTables_CellToolTipTextNeeded(object sender, DataGridViewCellToolTipTextNeededEventArgs e)
        {
           // e.ToolTipText = dgwTables. e.RowIndex e.ColumnIndex 
        }

        private void selectAllToolStripMenuItem_Click(object sender, EventArgs e)
        {
            for (int i = 0; i < dgwTables.Rows.Count; i++)
            {
                    ((Table)dgwTables.Rows[i].DataBoundItem).Include = true;
            }
            dgwTables.Refresh();
        }

        private void selectNoneToolStripMenuItem_Click(object sender, EventArgs e)
        {
            for (int i = 0; i < dgwTables.Rows.Count; i++)
            {
                ((Table)dgwTables.Rows[i].DataBoundItem).Include = false;
            }
            dgwTables.Refresh();
        }

        private void invertSelectionToolStripMenuItem_Click(object sender, EventArgs e)
        {
            for (int i = 0; i < dgwTables.Rows.Count; i++)
            {
                ((Table)dgwTables.Rows[i].DataBoundItem).Include = (!((Table)dgwTables.Rows[i].DataBoundItem).Include);
            }
            dgwTables.Refresh();
        }

        private void btnSingleAddTable_Click(object sender, EventArgs e)
        {
            
            oSingleTables.Add((string)cmbSingleTables.SelectedValue);
            dgwSingleTables.DataSource = null;
            dgwSingleTables.DataSource = oSingleTables.AsList;
            dgwSingleTables.Refresh();
        }

        private void dgwSingleTables_RowEnter(object sender, DataGridViewCellEventArgs e)
        {
            if (dgwSingleTables.Rows[e.RowIndex].DataBoundItem == null)
                return;
            dgwSingleColumns.DataSource = ((Table)dgwTables.Rows[e.RowIndex].DataBoundItem).Columns.AsList;
        }

        private void tsConfig_Click(object sender, EventArgs e)
        {
            frmConfig oFrm = new frmConfig();
            oFrm.ShowDialog();
        }

        private void toolStripButton1_Click(object sender, EventArgs e)
        {
            MessageBox.Show("Coming Soon.", "Script IT", MessageBoxButtons.OK, MessageBoxIcon.Information);
            //Help.ShowHelp(dgwTables, helpProvider1.HelpNamespace);
        }

        private void toolStripSplitButton1_ButtonClick(object sender, EventArgs e)
        {

        }

    }
}
